package org.agilelang.config;

import org.agilelang.object.ObjectAttribute;
import org.agilelang.object.ObjectClass;
import org.agilelang.object.ObjectClassAttribute;
import org.agilelang.object.ObjectFunction;
import org.agilelang.object.ObjectParam;
import org.agilelang.object.ObjectProject;
import org.agilelang.object.ObjectView;
import org.agilelang.object.Read;
import java.io.*;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import org.agilelang.config.FileStatic;

public class ScannerConfig {

    public static String word_name = "";//1
    public static String word_object = "";//2
    public static String word_function = "";//3
    public static char[] rule_declare = new char[]{'=', '.', '(', ')', ';'};//1
    public static char[] rule_assign = new char[]{'.', '(', ')', ';'};//2
    public static char[] rule_param = new char[]{'=', '"', '"', ','};//3
    public static int rule = 0;
    public static int lw = 1;
    //public static HashMap mapObjects = new HashMap();
    public static Map<String, ObjectClass> mapObjects = new HashMap<>();
    public static HashMap mapObjectsType = new HashMap();
    public static Map<String, String> attributes = new HashMap<>();
    public static String param = "";//1
    public static int line = 0;
    public ObjectProject agileproject = null;

    public static String path_xml_out = "";

    public ScannerConfig(String f, String path_xml_out) {
        this.path_xml_out = path_xml_out;
        this.agileproject = agileproject;

        String bufferIn;
        try {

            File fileDir = new File(f);

            BufferedReader leer = new BufferedReader(new InputStreamReader(new FileInputStream(fileDir), "UTF8"));

            //DataInputStream in = new DataInputStream(new FileInputStream(f));//leemos nuestro archivo de entrada
            try {
                //while ((bufferIn = in.readLine()) != null) {//mientras no lleguemos al fin del archivo...
                while ((bufferIn = leer.readLine()) != null) {

            //DataInputStream in = new DataInputStream(new FileInputStream(f));//leemos nuestro archivo de entrada
                    //try {
                    //while ((bufferIn = in.readLine()) != null) {//mientras no lleguemos al fin del archivo...
                    int i = 0;
                    String cad = bufferIn.trim();//eliminamos los espacios en blanco al incio o al final (pero no a la mitad)
                    line++;
                    while (i < cad.length()) {//recorremos la línea
                        char t = cad.charAt(i);//vamos leyendo caracter por caracter
                        if (cad.charAt(i) == '/' && cad.charAt(i + 1) == '/') {
                            break;
                        } else if (t == ';') {//fin de sentencia
                            System.out.println("fin-->" + t);
                            i = i + 1;
                            viewSentence();
                            //reset variables
                            word_object = "";
                            word_name = "";
                            word_function = "";
                            param = "";
                            lw = 1;
                            rule = 0;
                            attributes = new HashMap<String, String>();

                            continue;//pasamos al siguiente elemento
                        } else if (t == '"') {//aqui se visualiza los parametros
                            String value = "";
                            for (int j = i + 1; j < cad.length(); j++) {
                                char tt = cad.charAt(j);
                                //"
                                if (tt == '\\') {
                                    value += cad.charAt(j);
                                    i = j;
                                    j++;
                                    tt = cad.charAt(j);
                                    value += cad.charAt(j);
                                    i = j;
                                    continue;
                                }
                                if (tt == '"') {
                                    i = j + 1;
                                    break;
                                }
                                if (j == cad.length()) {
                                    break;//rompemos si llegamos al final de la línea
                                }
                                value += cad.charAt(j);
                                i = j;
                            }
                            attributes.put(param, value);

                            //System.out.println("param-->" + param +" - "+"value-->" + value);
                            continue;//pasamos al siguiente elemento
                        } else if (Character.isLetter(t)) {//comprobamos si es una letra
                            String ora = "";
                            ora += t;
                            int j = i + 1;
                            try {
                                while (Character.isLetterOrDigit(cad.charAt(j))) {
                                    ora += cad.charAt(j);
                                    j++;
                                    if (j == cad.length()) {
                                        break;
                                    }
                                }
                            } catch (Exception e) {
                                System.err.println("mal line " + line + " " + e.toString());
                                return;
                            }
                            i = j;
                            palabraReservada(ora);

                            continue;
                        }//end if si es variable
                        else if (!Character.isLetterOrDigit(t)) {
                            if (rule == 0 && t != ' ') {
                                //System.out.println("line-------------------------------------------->" + line);
                                evaluteRule(t);
                            }
                            i++;
                            continue;
                        }//end if si es diferente de letra y digito
                    }
                }//end while
            } catch (IOException e) {
            }
        } catch (FileNotFoundException e) {
        } catch (UnsupportedEncodingException ex) {
            Logger.getLogger(ScannerConfig.class.getName()).log(Level.SEVERE, null, ex);
        }

        result();
    }

    public static void evaluteRule(char c) {
        if (rule_declare[0] == c) {
            rule = 1;
            lw = 2;
            //System.out.println("******rule-->" + rule);
        } else if (rule_assign[0] == c) {
            rule = 2;
            lw = 2;
            //System.out.println("******rule-->" + rule);
        }
    }

    public static boolean palabraReservada(String cad) {
        if (lw == 1) {
            word_name = cad;
            //System.out.println("word_name -->" + word_name);

        } else if (lw == 2 && rule == 1) {
            word_object = cad;
            lw = 4;
            //System.out.println("word_object -->" + word_object);

        } else if (lw == 2 && rule == 2) {
            word_function = cad;
            //System.out.println("word_function -->" + word_function);
            lw = 4;

        } else if (lw == 3) {
            word_function = cad;
            //System.out.println("word_function -->" + word_function);
            lw = 4;
        } else if (lw == 4) {
            param = cad;
            //System.out.println("param -->" + param);

        }

        /*for (int i = 0; i < reservedword_object.length; i++) {
         if (cad.equals(reservedword_object[i])) {
         return true;
         }
         }*/
        return false;

    }

    public void viewSentence() {

        if (rule == 1) {
            System.out.println("****** Sentence Declare ******");
            System.out.println("word_name -->" + word_name);

            System.out.println("word_function -->" + word_function);
            if (word_object.equals("AgileConfig")) {
                if (word_function.equals("")) {
                    declareSentence();
                }
            }
            if (word_object.equals("AgileStructure")) {
                if (word_function.equals("")) {
                    declareSentence();
                }
            }
            if (word_object.equals("AgileSyntax")) {
                if (word_function.equals("")) {
                    declareSentence();
                }
            }

            /*for (Iterator<ObjectClass> it = list.iterator(); it.hasNext();) {
             ObjectClass agile_class = it.next();
             if (agile_class.getType().equals(word_object)) {
             System.out.println("word_object -->" + word_object);

             
             }
             }*/
        } else if (rule == 2) {
            System.out.println("****** Sentence Assign ******");
            System.out.println("word_name -->" + word_name);
            System.out.println("word_function -->" + word_function);
            assignSentence();

        }
        //System.out.println("-------------------------------------------------------");

    }

    public void declareSentence() {
        ObjectClass obj = new ObjectClass();
        obj.setName(word_name);
        obj.setType(word_object);
        if (word_object.equals("AgileConfig")) {
            System.err.println("------------------------------------");
        }
        for (Iterator<String> it = attributes.keySet().iterator(); it.hasNext();) {
            ObjectClassAttribute obj_attribute = new ObjectClassAttribute();
            String param_s = it.next();
            Object value_s = attributes.get(param_s);
            obj_attribute.setName(param_s);
            obj_attribute.setValue(value_s.toString());
            obj.addClassattribute(obj_attribute);
        }
        mapObjects.put(word_name, obj);
    }

    public void assignSentence() {
        ObjectClass obj = null;
        for (Iterator<String> it = mapObjects.keySet().iterator(); it.hasNext();) {
            String name = it.next();
            if (name.equals(word_name)) {
                obj = mapObjects.get(name);
                break;
            }
        }
        ObjectFunction func = new ObjectFunction();
        func.setName(word_function);

        for (Iterator<String> it = attributes.keySet().iterator(); it.hasNext();) {
            ObjectParam param = new ObjectParam();
            String param_s = it.next();
            param.setName(param_s);
            Object value_s = attributes.get(param_s);
            param.setValue(value_s.toString());
            func.getParams().add(param);
        }
        obj.getFunctions().add(func);

        /*if (word_function.equals("addView")) {
         AgileFunction func = new AgileFunction();
         func.setName(word_function);

         for (Iterator<String> it = attributes.keySet().iterator(); it.hasNext();) {
         AgileParam param = new AgileParam();
         String param_s = it.next();
         param.setName(param_s);
         Object value_s = attributes.get(param_s);
         param.setValue(value_s.toString());
         func.getParams().add(param);
         }
         obj.getFunctions().add(func);
         //---------------------------------------
         AgileView func2 = new AgileView();
         func.setName(word_function);

         for (Iterator<String> it = attributes.keySet().iterator(); it.hasNext();) {
         AgileParam param = new AgileParam();
         String param_s = it.next();
         param.setName(param_s);
         Object value_s = attributes.get(param_s);
         param.setValue(value_s.toString());
         func2.getParams().add(param);
         }
         obj.getViews().add(func2);
         }
         if (word_function.equals("addFunction")) {
         AgileFunction func = new AgileFunction();
         func.setName(word_function);

         for (Iterator<String> it = attributes.keySet().iterator(); it.hasNext();) {
         AgileParam param = new AgileParam();
         String param_s = it.next();
         param.setName(param_s);
         Object value_s = attributes.get(param_s);
         param.setValue(value_s.toString());
         func.getParams().add(param);
         }
         obj.getFunctions().add(func);
         }*/
        mapObjects.put(word_name, obj);

    }

    public static void result() {
        ObjectProject project = new ObjectProject();
        System.out.println("----------------------------------------------------------------");
        for (Iterator<String> it = mapObjects.keySet().iterator(); it.hasNext();) {
            String name = it.next();
            ObjectClass object = mapObjects.get(name);
            project.getClasses().add(object);
            System.out.println(object.getType().toString());
            System.out.println(object.getName().toString());

        }
        //--------------------
        JAXBContext jc = null;
        Marshaller marshaller;
        java.io.StringWriter sw = new StringWriter();
        try {
            jc = JAXBContext.newInstance(ObjectProject.class);
            marshaller = jc.createMarshaller();
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
            marshaller.marshal(project, sw);

        } catch (JAXBException ex) {
            System.out.println("Error --> " + ex.toString());
        }
        //System.out.println(sw.toString());
        Writer output = null;
        System.out.println(path_xml_out);
        File file = new File(path_xml_out);
        try {
            //output = new BufferedWriter(new FileWriter(file));

            output = new BufferedWriter(new OutputStreamWriter(
                    new FileOutputStream(file), "UTF8"));

            output.write(sw.toString());

            output.flush();
            output.close();
        } catch (IOException ex) {
            System.out.println(ex.toString());
        }
        /*try {

            
         PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(path_xml_out)));

         pw.print(sw.toString());
         pw.close();
         //System.out.println("XML Generate : " + path_xml + "\n");
         } catch (IOException e) {
         //System.out.println("ERROR : " + e.toString() + "\n");
         }*/

    }

    public static void main(String ar[]) {

        /*String path_xml = "E:\\agile\\AgileLang\\Test\\syntax.xml";
         Read rd = new Read();
         ObjectProject agileproject = rd.process(path_xml);
         Scanner dosPrueba1 = new Scanner("E:\\agile\\AgileLang\\Test\\source.agile", agileproject, "E:\\agile\\AgileLang\\Test\\out.xml");
         */
        String path_xml = "E:\\agile\\AgileLang\\Test\\old\\syntax.xml";
        Read rd = new Read();
        ObjectProject agileproject = rd.process(path_xml);
        ScannerConfig dosPrueba1 = new ScannerConfig("E:\\agile\\AgileLang\\Test\\java_swing.config", "E:\\agile\\AgileLang\\Test\\out.xml");

    }
}
